#ifndef __M_USER_H__
#define __M_USER_H__

#include "../mqcommon/logger.hpp"
#include "../mqcommon/sqliter.hpp"
#include "../mqcommon/spliter.hpp"
#include "../mqcommon/filer.hpp"

#include <iostream>
#include <unordered_map>
#include <string>
#include <mutex>
#include <memory>
#include <assert.h>
#include <sstream>
namespace zhong
{
    enum USERLEVEL
    {
        MANAGER = 1,
        CONSUMER = 2,
        PRODUCER = 3
    };
    struct User
    {
        using ptr = std::shared_ptr<User>;
        User() {}
        User(const std::string &user_name, const std::string &password, USERLEVEL level, bool durable)
            : _user_name(user_name), _password(password), _level(level), _durable(durable) {}

        std::string _user_name;
        std::string _password;
        USERLEVEL _level;
        bool _durable;
    };

    class UserMapper
    {
    public:
        UserMapper(const std::string &data_base_file)
            : _sqliter(data_base_file)
        {
            std::string path = Filer::parentDirectory(data_base_file); // 获取父级目录
            Filer::createDirectory(path);                              // 创建目录
            assert(_sqliter.open());                                   // 创建数据库
            createTable();
        }
        void createTable()
        {
            // 构造表的创建语句
            std::string sql_create = "create table if not exists user_table(name varchar(128) primary key,\
                                                                            password varchar(128), \
                                                                            level int,\
                                                                            durable int);";
            if (_sqliter.exec(sql_create, nullptr, nullptr) == false)
            {
                ERR_LOG("创建用户数据库失败");
                abort(); // 退出程序
            }
        }
        void removeTable()
        {
            std::string sql_remove = "drop table if exists user_table";
            if (_sqliter.exec(sql_remove, nullptr, nullptr) == false)
            {
                ERR_LOG("删除用户数据库失败");
                abort(); // 退出程序
            }
        }
        bool insert(User::ptr &user)
        {
            std::stringstream ss;
            ss << "insert into user_table values(";
            ss << "'" << user->_user_name << "', ";
            ss << user->_password << ", ";
            ss << user->_level << ", ";
            ss << "'" << user->_durable << "');";
            if (_sqliter.exec(ss.str(), nullptr, nullptr) == false)
            {
                INFO_LOG("添加用户数据失败, 错误原因[%s]", strerror(errno));
                return false; // 退出程序
            }
            return true;
        }
        void remove(const std::string &user_name)
        {
            std::string sql_delete = "delete from user_table where name='" + user_name + "';";
            if (_sqliter.exec(sql_delete, nullptr, nullptr) == false)
            {
                INFO_LOG("删除用户数据失败");
                return; // 退出程序
            }
        }
        // 查询交换机数据
        std::unordered_map<std::string, User::ptr> getAllUser()
        {
            std::unordered_map<std::string, User::ptr> ret;
            std::string sql_select = "select name, password, level, durable from user_table";
            _sqliter.exec(sql_select, selectCallback, &ret); // 获取每一行交换机数据到ret中
            return ret;
        }

    private:
        static int selectCallback(void *args, int numcol, char **row, char **fields)
        {
            auto ret = (std::unordered_map<std::string, User::ptr> *)args; // 获取一个交换机存储的哈希结构
            auto user = std::make_shared<User>();                          // 获取一台交换机
            // 按顺序添加交换机数据到ret中
            user->_user_name = row[0];
            user->_password = row[1];
            user->_level = (USERLEVEL)std::stoi(row[2]);
            user->_durable = (bool)std::stoi(row[3]);

            ret->insert(std::make_pair(user->_user_name, user));
            return 0;
        }

    private:
        Sqliter _sqliter;
    };

    class UserManager
    {
    public:
        using ptr = std::shared_ptr<UserManager>;
        UserManager(const std::string &data_base_file)
            : _mapper(data_base_file + "/meta.db")
        {
            _users = _mapper.getAllUser();
        }
        bool declareUser(const std::string &user_name,
                         const std::string &password,
                         USERLEVEL level,
                         bool durable)
        {
            auto it = _users.find(user_name);
            if (it != _users.end())
            {
                INFO_LOG("User[%s]已存在", user_name.c_str());
                return true;
            }
            User::ptr user = std::make_shared<User>(user_name, password, level, durable);
            if (user->_durable == true)
            {
                _mapper.insert(user);
            }
            _users.insert(std::make_pair(user->_user_name, user));
            return true;
        }
        void deleteUser(const std::string &name, const std::string &password)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _users.find(name);
            if (it == _users.end())
            {
                return; // 不存在直接返回
            }
            if (password != it->second->_password)
            {
                INFO_LOG("确认User[%s]密码错误，删除失败", name.c_str());
                return;
            }
            if (it->second->_durable == true)
                _mapper.remove(name);

            _users.erase(name);
        }
        User::ptr selectUser(const std::string &name, const std::string &password)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _users.find(name);
            if (it == _users.end())
            {
                INFO_LOG("不存在用户[%s]", name.c_str());
                return User::ptr();
            }
            if(password != it->second->_password)
            {
                INFO_LOG("用户[%s]密码错误", name.c_str());
                return User::ptr();
            }
            return it->second;
        }
        bool exist(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _users.find(name);
            if (it == _users.end())
            {
                return false;
            }
            return true;
        }
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _users.size();
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _users.clear();
        }

    private:
        std::mutex _mutex;
        UserMapper _mapper;
        std::unordered_map<std::string, User::ptr> _users;
    };
}
#endif